//
//  main.cpp
//  
//
//  Created by Kun Zhao on 12/05/29.
//  Copyright (c) 2012 Kyoto University. All rights reserved.
//

#include <kvs/UnstructuredVolumeImporter>
#include <kvs/UnstructuredVolumeObject>
#include <kvs/Timer>
#include <cstdio>
#include <kvs/CommandLine>
#include <kvs/BitArray>

class Argument : public kvs::CommandLine
{
public:
    std::string basename;
    int step;
    float tolerance;
    
    Argument( int argc, char** argv ) : CommandLine( argc, argv )
    {
        add_help_option();
        add_option( "f", "base name of the time varying data", 1, true );
        add_option( "s", "the steps of the time varying data", 1, true );
        add_option( "t", "tolerance of the CT", 1, false );
    }
    
    void exec()
    {
        tolerance = 0.001;
        if( !this->parse() ) exit( EXIT_FAILURE );
        if( this->hasOption( "f" ) ) basename = this->optionValue<std::string>( "f" );
        if( this->hasOption( "s" ) ) step = this->optionValue<int>( "s" );
        if( this->hasOption( "t" ) ) tolerance = this->optionValue<float>( "t" );
    }
    
};

std::string CreateString( std::string basename, int i, std::string extension  )
{
    char buf[10];
    sprintf( buf, "%03d", i );
    return( basename + std::string( buf ) + extension );
}

int main( int argc, char** argv )
{
    Argument param( argc, argv );
    param.exec();
    
    kvs::UnstructuredVolumeObject* volume[param.step];
    for ( int i = 0; i < param.step; i++ )
    {
        volume[i] = new kvs::UnstructuredVolumeImporter( CreateString( param.basename, i, ".kvsml" ) );   
    }
    
    for ( int index = 1; index < param.step; index++ ) 
    {
        kvs::UnstructuredVolumeObject* object1 = volume[index - 1];
        kvs::UnstructuredVolumeObject* object2 = volume[index];
        
        kvs::Timer time;
        time.start();
        float range =(float)( object1->maxValue() - object1->minValue() );
        float toleranceError = range * param.tolerance;    
        
        unsigned int NumberOfVertices = object1->nnodes();
        unsigned int NumberOfCells = object1->ncells();
        const unsigned int* pconnections = object1->connections().pointer();
        
        const float* value1 = (float*)object1->values().pointer();
        const float* value2 = (float*)object2->values().pointer();
        
        bool* VerticesTable = new bool[NumberOfVertices];
        bool* CellsTable = new bool[NumberOfCells];
        
        //Make vertices table
        for ( size_t i = 0; i < NumberOfVertices; i++ ) 
        {
            if ( fabs(value1[i] - value2[i]) <= toleranceError )
                VerticesTable[i] = (bool)0;
            else
                VerticesTable[i] = (bool)1;
        }
        
        //Make cells coherence table
        size_t CountChange = 0;
        size_t CountNoChange = 0;
        for( size_t i = 0; i < NumberOfCells; i++ )
        {
            if(VerticesTable[*(pconnections++)] ||
               VerticesTable[*(pconnections++)] ||
               VerticesTable[*(pconnections++)] ||
               VerticesTable[*(pconnections++)] ||
               VerticesTable[*(pconnections++)] ||
               VerticesTable[*(pconnections++)] ||
               VerticesTable[*(pconnections++)] ||
               VerticesTable[*(pconnections++)] )
            { CellsTable[i] = (bool)0; CountChange++; } // no coherence
            else
            { CellsTable[i] = (bool)1; CountNoChange++; } // coherence
            //        CellsTable[i] = (bool)1;
        }
        
        delete VerticesTable;
        
        std::cout << (float)CountNoChange/NumberOfCells << std::endl;
        time.stop();
        std::cout << "processing time: " << time.msec() << std::endl;
        
        FILE* fp;
        fp = fopen( CreateString( "CT", index, ".bin" ).c_str(), "wb" );
        fwrite( CellsTable, sizeof(bool), NumberOfCells, fp );
        fclose( fp );
        delete CellsTable;
    }
}